package net.qiqbframework.spring.config;

import net.qiqbframework.config.Configuration;
import net.qiqbframework.config.Configurer;
import net.qiqbframework.spring.event.QiqbStartedEvent;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.SmartLifecycle;
import org.springframework.lang.NonNull;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

public class SpringQiqbConfiguration implements FactoryBean<Configuration>, SmartLifecycle {

    public static final int LIFECYCLE_PHASE = SmartLifecycle.DEFAULT_PHASE
            - 1024 // this puts us next to the "graceful" stop of web servers...
            - 1024 // this puts us next to the regular, start and non-graceful stop of web servers...
            - 1024; // we place ourselves healthily below that, starting before web servers and stopping after.

    private final Configurer configurer;
    private final AtomicBoolean isRunning = new AtomicBoolean(false);
    private final AtomicReference<Configuration> configuration = new AtomicReference<>();
    private ApplicationContext applicationContext;

    /**
     * Initialize this {@link Configuration} instance.
     *
     * @param configurer The configurer to get the {@link Configuration} from.
     */
    public SpringQiqbConfiguration(Configurer configurer) {
        this.configurer = configurer;
    }

    @NonNull
    @Override
    public Configuration getObject() {
        Configuration c = configuration.get();
        if (c != null) {
            return c;
        }
        configuration.compareAndSet(null, configurer.buildConfiguration());
        return configuration.get();
    }

    @Override
    public Class<?> getObjectType() {
        return Configuration.class;
    }

    @Override
    public void start() {
        if (isRunning.compareAndSet(false, true)) {
            getObject().start();
            this.applicationContext.publishEvent(new QiqbStartedEvent());
        }
    }

    @Override
    public void stop() {
        Configuration c = this.configuration.get();
        if (isRunning.compareAndSet(true, false) && c != null) {
            c.shutdown();
        }
    }

    @Override
    public boolean isRunning() {
        return isRunning.get();
    }

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public int getPhase() {
        return LIFECYCLE_PHASE;
    }
}
